/*
 * PhotonRTOS础光实时操作系统 -- 中断头文件
 *
 * Copyright (C) 2022, 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Baoyou Xie <xiebaoyou@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#ifndef _OS_IRQ_H
#define _OS_IRQ_H

#include <photon/string.h>
#include <photon/smp_lock.h>
#include <asm/irq.h>

/**
 * NR_IRQS，中断控制器可以支持的硬件最大中断数目
 *
 */
#ifndef NR_IRQS
#define NR_IRQS 128U
#endif

enum {
	__HWIRQ_TYPE_EDGE_RISING,
	__HWIRQ_TYPE_EDGE_FALLING,
	__HWIRQ_TYPE_LEVEL_HIGH,
	__HWIRQ_TYPE_LEVEL_LOW,

	__HWIRQ_DISALBE_ISR,
};

/**
 * 硬件中断的类型
 */
#define HWIRQ_TYPE_NONE		0U
#define HWIRQ_TYPE_EDGE_RISING	(1U << __HWIRQ_TYPE_EDGE_RISING)
#define HWIRQ_TYPE_EDGE_FALLING	(1U << __HWIRQ_TYPE_EDGE_FALLING)
#define HWIRQ_TYPE_EDGE_MASK						\
		(HWIRQ_TYPE_EDGE_RISING | HWIRQ_TYPE_EDGE_FALLING)

#define HWIRQ_TYPE_LEVEL_HIGH	(1U << __HWIRQ_TYPE_LEVEL_HIGH)
#define HWIRQ_TYPE_LEVEL_LOW		(1U << __HWIRQ_TYPE_LEVEL_LOW)

#define HWIRQ_TYPE_LEVEL_MASK						\
		(HWIRQ_TYPE_LEVEL_HIGH | HWIRQ_TYPE_LEVEL_LOW)

#define HWIRQ_TRIGGER_TYPE_MASK						\
	(HWIRQ_TYPE_EDGE_MASK | HWIRQ_TYPE_LEVEL_MASK)

#define HWIRQ_DISALBE_ISR		(1U << __HWIRQ_DISALBE_ISR)

extern uint32_t irq_count;

/* 中断处理函数原型 */
typedef void (*isr_handler_f)(void);

/**
 * 中断描述
 */
struct irq_desc {
	/**
	 * 描述符名称
	 */
	char		*name;
	/**
	 * 中断号
	 */
	uint32_t	hw_irq;
	/**
	 * 中断标志
	 */
	uint32_t	irqflags;
	/**
	 * 回调函数
	 */
	isr_handler_f	handler;
	/**
	 * 触发次数
	 */
	uint32_t occur_count;
	/**
	 * 最大允许的触发次数阈值，超过会强制禁用irq
	 */
	uint32_t occur_threshold;
	/**
	 * 中断优先级
	 */
	uint32_t pri;
	/**
	 * AUTOSAR 二类中断标志
	*/
	bool isr2;
};

/**
 * 中断控制器描述符
 */
struct irq_controller {
	/**
	 * 设置某个中断的类型
	 */
	int32 (*set_trigger_type)(uint32_t hw_irq,
			unsigned int type);
	/**
	 * 屏蔽某个中断
	 */
	void (*mask)(uint32_t hw_irq);
	/**
	 * 取消屏蔽
	 */
	void (*unmask)(uint32_t hw_irq);
	/**
	 * ack应答某个中断
	 */
	void (*ack)(uint32_t hw_irq);
	/**
	 * 清除挂起的标志位
	*/
	void (*clear_pending)(uint32_t hw_irq);
	/**
	 * 查询中断状态
	*/
	uint32 (*get_status)(uint32_t hw_irq);
	/**
	 * 得到distributer硬件中断优先级
	*/
	uint32_t (*get_priority)(uint32_t hw_irq);
	/**
	 * 设置中断优先级
	 */
	int32_t (*set_priority)(uint32_t hw_irq, uint32_t pri);
};

extern struct irq_desc *os_irq_desc[NR_IRQS];
extern struct irq_controller os_irq_controller;

/**
 * 得到中断号对应的中断描述符
 */
struct irq_desc *get_irq_desc(uint32_t hw_irq);

static inline uint32_t get_irq_trigger_type(uint32_t irq)
{
	struct irq_desc *desc = get_irq_desc(irq);

	return desc ? (desc->irqflags & HWIRQ_TRIGGER_TYPE_MASK) : 0U;
}

void irq_enable(uint32_t hw_irq);
void irq_disable(uint32_t hw_irq);
void init_irq_controller(void);
void clear_irq_pending(uint32_t hw_irq);
void mask_irq(uint32_t hw_irq);
void unmask_irq(uint32_t hw_irq);
int32_t set_irq_priority(uint32_t hw_irq, uint32_t pri);
uint32_t get_irq_priority(uint32_t hw_irq);
uint32_t get_irq_status(uint32_t hw_irq);
int32_t set_irq_trigger_type(uint32_t irq, uint32_t type);

extern int32_t do_hard_irq(uint32_t hw_irq, void *regs);

#define hardirq_count()	(preempt_count() & HARDIRQ_MASK)
#define softirq_count()	(preempt_count() & SOFTIRQ_MASK)
#define irq_count()	(preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK))

#define in_hard_interrupt() (hardirq_count())
#define in_interrupt()		(irq_count())

#define ISR_FUN(Name) void Name(void)

#define ISR_ATTR(Name) OS_INT_ATTR_##Name
#define DeclareInterrupt(Name, Irqno, Irqflags, OccurThreshold, PRI, ISR2) \
	extern ISR_FUN(Name);						\
	struct irq_desc ISR_ATTR(Name) =				\
	{								\
		.name = #Name,						\
		.hw_irq = Irqno,					\
		.irqflags = Irqflags,					\
		.handler = Name,				\
		.occur_count = 0,					\
		.occur_threshold = OccurThreshold,			\
		.isr2 = ISR2, 						\
		.pri = PRI,						\
	}

extern void init_IRQ(void);
extern int32_t init_interrupt(void);
extern void check_irq_storm(void);

#endif /* _OS_IRQ_H */
